using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
using SumerCoreDevOps.Application.NodeRegistration.Commands;
using SumerCoreDevOps.Application.NodeRegistration.Queries;
using SumerCoreDevOps.Domain.Entities;
using SumerCoreDevOps.Infrastructure.NodeRegistration;
using SumerCoreDevOps.Application.Dtos.Requests.NodeRegistration;
namespace SumerCoreDevOps.ControlApi.Controllers;

/// <summary>
/// 节点注册令牌管理 API
/// </summary>
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class NodeRegistrationController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<NodeRegistrationController> _logger;
    private readonly NodeJoinTokenManager _tokenManager;
    private readonly IConfiguration _configuration;

    public NodeRegistrationController(
        IMediator mediator,
        ILogger<NodeRegistrationController> logger,
        NodeJoinTokenManager tokenManager,
        IConfiguration configuration)
    {
        _mediator = mediator;
        _logger = logger;
        _tokenManager = tokenManager;
        _configuration = configuration;
    }

    /// <summary>
    /// 生成注册令牌
    /// </summary>
    /// <param name="request">生成令牌请求对象</param>
    /// <returns>返回包含新生成的令牌完整信息(令牌ID、令牌值、名称、描述、过期时间、最大使用次数等)、注册命令、注册链接URL以及注册说明的对象;发生错误时返回500状态码和错误详情</returns>
    [HttpPost("token/generate")]
    public async Task<ActionResult<object>> GenerateToken([FromBody] GenerateTokenRequest request)
    {
        try
        {
            var token = await _mediator.Send(new GenerateTokenCommand(
                request.Name,
                request.Description,
                request.ExpiresInHours,
                request.MaxUsageCount,
                request.CreatedBy
            ));

            // 获取服务器配置
            var httpUrl = $"{Request.Scheme}://{Request.Host}"; // 完整的 HTTP URL
            var tcpPort = _configuration.GetValue<int>("TcpServer:Port", 9090);
            var executeNodePort = _configuration.GetValue<int?>("ExecuteNode:DefaultPort");

            // 生成注册命令和链接
            var command = _tokenManager.GenerateRegistrationCommand(token.Token, httpUrl, tcpPort);
            var link = _tokenManager.GenerateRegistrationLink(token.Token, httpUrl, executeNodePort);

            return Ok(new
            {
                message = "令牌生成成功",
                token = new
                {
                    id = token.Id,
                    token = token.Token,
                    name = token.Name,
                    description = token.Description,
                    expiresAt = token.ExpiresAt,
                    maxUsageCount = token.MaxUsageCount,
                    usedCount = token.UsedCount,
                    createdAt = token.CreatedAt
                },
                registrationCommand = command,
                registrationLink = link,
                registrationUrl = link, // 添加一个清晰的字段名
                instructions = new
                {
                    step1 = "在执行节点服务器的浏览器中打开下方的注册链接",
                    step2 = "或者复制下方的注册命令在执行节点服务器上运行",
                    step3 = "节点将自动连接到控制面板并完成注册"
                }
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "生成令牌失败");
            return StatusCode(500, new { message = "生成令牌失败", error = ex.Message });
        }
    }

    /// <summary>
    /// 获取所有令牌
    /// </summary>
    /// <param name="includeRevoked">是否包含已撤销的令牌</param>
    /// <returns>返回令牌列表,每个令牌包含令牌ID、令牌值、名称、描述、状态、过期时间、使用次数等信息;如果includeRevoked为false则只返回有效令牌;发生错误时返回500状态码和错误详情</returns>
    [HttpGet("token")]
    public async Task<ActionResult<List<NodeJoinToken>>> GetAllTokens([FromQuery] bool includeRevoked = false)
    {
        try
        {
            var tokens = await _mediator.Send(new GetAllTokensQuery(includeRevoked));
            return Ok(tokens);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取令牌列表失败");
            return StatusCode(500, new { message = "获取令牌列表失败", error = ex.Message });
        }
    }

    /// <summary>
    /// 获取令牌详情
    /// </summary>
    /// <param name="tokenId">令牌ID</param>
    /// <returns>返回指定令牌的完整信息对象,包括令牌ID、令牌值、名称、描述、状态、过期时间、最大使用次数、已使用次数、创建时间等;如果令牌不存在则返回404状态码和提示信息;发生错误时返回500状态码和错误详情</returns>
    [HttpGet("token/{tokenId}")]
    public async Task<ActionResult<NodeJoinToken>> GetTokenById(long tokenId)
    {
        try
        {
            var token = await _mediator.Send(new GetTokenQuery(tokenId));
            if (token == null)
            {
                return NotFound(new { message = "令牌不存在" });
            }

            return Ok(token);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取令牌详情失败: {TokenId}", tokenId);
            return StatusCode(500, new { message = "获取令牌详情失败", error = ex.Message });
        }
    }

    /// <summary>
    /// 验证令牌
    /// </summary>
    /// <param name="request">验证令牌请求对象</param>
    /// <returns>返回验证结果对象,包含isValid布尔值(令牌是否有效)和errorMessage错误信息(仅在无效时返回);令牌可能因过期、已撤销、使用次数耗尽等原因无效;发生错误时返回500状态码和错误详情</returns>
    [HttpPost("token/validate")]
    public async Task<ActionResult<object>> ValidateToken([FromBody] ValidateTokenRequest request)
    {
        try
        {
            var (isValid, errorMessage) = await _mediator.Send(new ValidateTokenQuery(request.Token));

            return Ok(new
            {
                isValid,
                errorMessage = isValid ? null : errorMessage
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "验证令牌失败");
            return StatusCode(500, new { message = "验证令牌失败", error = ex.Message });
        }
    }

    /// <summary>
    /// 撤销令牌
    /// </summary>
    /// <param name="tokenId">令牌ID</param>
    /// <param name="request">撤销令牌请求对象</param>
    /// <returns>返回200状态码和成功提示信息;撤销后的令牌将立即失效且不能被恢复;如果令牌不存在或已被撤销则返回400状态码和错误提示;发生错误时返回500状态码和错误详情</returns>
    [HttpPost("token/{tokenId}/revoke")]
    public async Task<ActionResult> RevokeToken(long tokenId, [FromBody] RevokeTokenRequest request)
    {
        try
        {
            await _mediator.Send(new RevokeTokenCommand(tokenId, request.Reason, request.RevokedBy));
            return Ok(new { message = "令牌已撤销" });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "撤销令牌失败: {TokenId}", tokenId);
            return StatusCode(500, new { message = "撤销令牌失败", error = ex.Message });
        }
    }

    /// <summary>
    /// 删除令牌
    /// </summary>
    /// <param name="tokenId">令牌ID</param>
    /// <returns>返回200状态码和成功提示信息;只有未使用的令牌可以被删除,已使用的令牌只能撤销;如果令牌不存在或已被使用则返回400状态码和错误提示;发生错误时返回500状态码和错误详情</returns>
    [HttpDelete("token/{tokenId}")]
    public async Task<ActionResult> DeleteToken(long tokenId)
    {
        try
        {
            await _mediator.Send(new DeleteTokenCommand(tokenId));
            return Ok(new { message = "令牌已删除" });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "删除令牌失败: {TokenId}", tokenId);
            return StatusCode(500, new { message = "删除令牌失败", error = ex.Message });
        }
    }

    /// <summary>
    /// 获取注册说明
    /// </summary>
    /// <returns>返回节点注册说明对象,包括注册步骤、服务器信息(主机、TCP端口)、示例命令以及注意事项;用于指导用户完成节点注册流程</returns>
    [HttpGet("instructions")]
    public ActionResult<object> GetInstructions()
    {
        var serverHost = _configuration.GetValue<string>("Server:Host") ?? "localhost";
        var tcpPort = _configuration.GetValue<int>("TcpServer:Port", 9090);

        return Ok(new
        {
            title = "节点注册说明",
            steps = new[]
            {
                "步骤 1: 在控制面板生成注册令牌",
                "步骤 2: 复制生成的注册命令",
                "步骤 3: 在执行节点服务器上安装节点代理程序",
                "步骤 4: 运行注册命令完成节点注册",
                "步骤 5: 在控制面板查看节点状态"
            },
            serverInfo = new
            {
                host = serverHost,
                tcpPort,
                exampleCommand = $"./node-agent register --server {serverHost}:{tcpPort} --token <YOUR_TOKEN>"
            },
            notes = new[]
            {
                "令牌默认有效期为 24 小时",
                "令牌默认只能使用 1 次",
                "可以自定义令牌的有效期和使用次数",
                "已使用的令牌可以撤销但不能删除",
                "未使用的令牌可以直接删除"
            }
        });
    }
}
